<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手写继承-原型链继承</title>
</head>
<body>
    <script>
        // 1、原型链继承
        function Father(sex){
            this.name="quan"
            this.do=["打游戏","刷抖音","等消息"]
            this.sex=sex
        }
        Father.prototype.sayHi=function(){
            console.log('Im '+this.name)
        }
        function Son(sex){
            this.age=21
            // this.sex=sex      // 但是，这个值必定会影响所有子类的对象实例，相当于子类构造函数 擅作主张 给所有对象实例的属性提前 赋了值。这样写是不太符合面向对象编程的规则的。
        }
        // 子类的prototype为父类的实例（核心思想）
        // Son.prototype=new Father(this.sex)     //这里可以传一个参数上去，但是必须在Son加this.sex=sex，但是这里加了Son的实例就已经有了这个属性，Father里面在加好像也没什么意义(证明了出现的问题二)，影响了其他对象实例（自我理解，有什么错误，欢迎交流）
        Son.prototype=new Father()
        // 这里给原型添加的方法，一定要在替换原型的后面(如果是给实例添加属性和方法，可以放在构造函数里面),这里是替换原型，如果加前面就加到一开始的默认的原型上面去了
        Son.prototype.sayAge=function(){
            console.log('Im '+this.age)
        }
        let instance1=new Son()
        instance1.sayHi()      //Im quan
        instance1.sayAge()     //Im 21
        let instance2=new Son()
        instance2.do.push('看直播')
        // 1、这里反映了原型链继承的第一个问题-----------来自原型对象的所有属性被所有实例共享
        console.log(instance1.do)        //["打游戏","刷抖音","等消息","看直播"]
        console.log(instance2.do)        //["打游戏","刷抖音","等消息","看直播"]

        instance1.name="ddd"             //这里是在实例上添加属性，以后访问的时候，直接就是访问对象的，直接屏蔽原型的同名属性
        instance1.__proto__.name="fff"   //这里就是访问原型的属性，这样instance2的原型中name也为fff，证明了出现的问题一，不只是包含引用类型值的原型属性会被所有实例共享
        console.log(instance1.name)      //ddd
        console.log(instance2.name)      //fff
        // 2、这里反映了原型链继承的第二个问题-----------不能向超类型的构造函数值传递参数,实际上，应该说没有办法在不影响所有对象实例的情况下向超类型的构造函数值传递参数
        let instance3=new Son('男')
        console.log(instance3.sex)       //undefined
    </script>
</body>
</html>